package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"strconv"
	"strings"
)

func socks5proxy1() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	server, err := net.Listen("tcp", ":1080")
	if err != nil {
		log.Println("Listen failed:", err)
		return
	}

	for {
		client, err := server.Accept()
		if err != nil {
			log.Println("Accept failed:", err)
			continue
		}
		go handleNewClient1(client)
	}
}

func handleNewClient1(client net.Conn) {
	defer client.Close()

	log.Println("Accept client", client.RemoteAddr())

	var b [1024]byte
	n, err := client.Read(b[:])
	if err != nil {
		log.Println(err)
		return
	}

	if b[0] == 0x05 {
		// 只处理Socks5协议
		// 客户端回应：Socks服务端不需要验证方式
		client.Write([]byte{0x05, 0x00})

		// 等待客户端发来目标主机地址信息
		n, err = client.Read(b[:])
		log.Println(">>", b[:n])

		var host, port string

		switch b[3] {
		case 0x01: // IP V4
			host = net.IPv4(b[4], b[5], b[6], b[7]).String()
		case 0x03: // 域名
			host = string(b[5 : n-2]) // b[4]表示域名的长度
		case 0x04: // IP V6
			ipv6 := fmt.Sprintf("%X", b[4:20])
			if strings.HasPrefix(ipv6, "000000000000FFFE") {
				slotId, _ := strconv.Atoi(ipv6[16:20])
				portId, _ := strconv.Atoi(ipv6[20:24])
				host = net.IPv4(b[16], b[17], b[18], b[19]).String()
				log.Println("xtip:", slotId, portId, host)
			} else {
				host = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
			}
		}
		port = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1]))

		// 建立到目标主机的连接
		log.Println("Connect to", net.JoinHostPort(host, port))
		target, err := net.Dial("tcp", net.JoinHostPort(host, port))
		if err != nil {
			log.Println(err)
			return
		}
		defer target.Close()

		// 响应客户端连接成功
		client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
		log.Printf("%s <=> (%s = %s) <=> %s\r\n", client.RemoteAddr(), client.LocalAddr(), target.LocalAddr(), target.RemoteAddr())

		// 进行转发
		go io.Copy(target, client)
		io.Copy(client, target)
	}
}
